package com.ferry.protocol;

import com.ferry.protocol.payload.PayloadHolder;
import com.ferry.protocol.payload.RequestPayload;
import com.ferry.protocol.payload.ResponsePayload;
import com.ferry.serial.api.SerializerType;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;

/**
 * Created by daiyong
 */
@ChannelHandler.Sharable
public class ProtocolEncoder extends MessageToByteEncoder<PayloadHolder> {

	@Override
	protected void encode(ChannelHandlerContext ctx, PayloadHolder msg, ByteBuf out) throws Exception {
		if (msg instanceof RequestPayload) {
			doEncodeRequest((RequestPayload) msg, out);
		} else if (msg instanceof ResponsePayload) {
			doEncodeResponse((ResponsePayload) msg, out);
		} else {
			throw new IllegalArgumentException("encode error");
		}
	}

	@Override
	protected ByteBuf allocateBuffer(ChannelHandlerContext ctx, PayloadHolder msg, boolean preferDirect) throws Exception {
		if (preferDirect) {
			return ctx.alloc().ioBuffer(ProtocolHeader.HEADER_SIZE + msg.size());
		} else {
			return ctx.alloc().heapBuffer(ProtocolHeader.HEADER_SIZE + msg.size());
		}
	}

	private void doEncodeRequest(RequestPayload request, ByteBuf out) {
		long invokeId = request.invokeId();
		byte[] bytes = request.bytes();
		out.writeShort(ProtocolHeader.MAGIC)
				.writeByte(MessageType.REQUEST.getCode())
				.writeByte(SerializerType.HESSIAN.getCode())
				.writeByte(StatusCode.OK.getCode())
				.writeLong(invokeId)
				.writeInt(bytes.length)
				.writeBytes(bytes);

	}

	private void doEncodeResponse(ResponsePayload response, ByteBuf out) {
		byte status = response.status();
		long invokeId = response.id();
		byte[] bytes = response.bytes();

		out.writeShort(ProtocolHeader.MAGIC)
				.writeByte(MessageType.RESPONSE.getCode())
				.writeByte(response.serializerCode())
				.writeByte(status)
				.writeLong(invokeId)
				.writeInt(bytes.length)
				.writeBytes(bytes);
	}


}
